
#include "xlibrary_config.h"

#if LIBARARY_ALERT_ENABLE
#include <string.h>
#include "alert.h"

#include "log.h"

static alert_t m_alert_handles[ NUMS_OF_ALERT ];
static uint8_t m_count_of_alerts = 0; 


static alert_desc_t alert_desc;


const alert_desc_t* alert_get_desc(void)
{
    return &alert_desc;
}

void alert_on_timer_timeout_handler(void * pcontext)
{
    // LOG_INFO1("[%s]: timer timeout \r\n", FORMAT_STRING( __FUNCTION__ ) );
    
    if( alert_desc.update )
    {
        return ;
    }
    alert_desc.working  = true; 

    bool completed = true;
    for(int i = 0; i < m_count_of_alerts; i++)
    {
        if( m_alert_handles[i].enabled == ALERT_DISABLE)
        {
            continue;
        }

        alert_t * p_alert = &m_alert_handles[i];
        completed = false;

        p_alert->work.timer ++;
        if( p_alert->work.threshold == 0)
        {
            p_alert->enabled = ALERT_DISABLE;
            continue;
        }

        if( p_alert->work.timer < p_alert->work.threshold)
        {
            continue;
        }
        
        p_alert->work.timer = 0;
        if( p_alert->on )
        {
            if( p_alert->handle )
            {
                p_alert->handle( ALERT_OFF ); // turn off
            }
            p_alert->on = ALERT_OFF;

            p_alert->work.count ++;
            if( p_alert->work.count >= p_alert->conf.count)
            {
                p_alert->work.count = 0; 
                p_alert->work.cycle ++;
                if( p_alert->work.cycle < p_alert->conf.cycle)
                {
                    p_alert->work.threshold = p_alert->conf.delay;
                }
                else
                {
                    p_alert->enabled = ALERT_DISABLE;
                    #if ALERT_HAS_CALLBACK_HANDLE
                    if( p_alert->completed)
                    {
                        p_alert->completed( i );
                    }
                    #endif
                }
            }
            else
            {
                p_alert->work.threshold = p_alert->conf.time_off;
            }
        }
        else{
            if( p_alert->handle )
            {
                p_alert->handle( ALERT_ON ); // turn on 
            }
            p_alert->on = ALERT_ON;
            p_alert->work.threshold = p_alert->conf.time_on;
        }
        
    }

    if( completed )
    {
        alert_desc.working = false;
        alert_timer_stop();
    }

}


void alert_update(const alert_conf_t * p_conf, int idx)
{
    if( idx >= m_count_of_alerts ){
        return;
    }

    alert_desc.update = true;

    alert_t * p_alert = & m_alert_handles[idx];
    p_alert->conf = *p_conf;

    if( p_alert->enabled && p_alert->addr == (uint32_t)p_conf )
    {
        p_alert->work.count = 0;
        p_alert->work.cycle = 0;
        p_alert->work.threshold = p_alert->conf.time_on;
        alert_desc.update = false; 
        return;
    }
    p_alert->addr = (uint32_t)p_conf;

    if( p_alert->conf.time_on == 0)
    {
        if(p_alert->handle)
        {
            p_alert->handle( ALERT_OFF );
        }

        p_alert->enabled = ALERT_DISABLE;
        alert_timer_stop();
    }
    else if( p_alert->conf.time_off == 0)
    {
        if( p_alert->handle )
        {
            p_alert->handle( ALERT_ON );
        }
        p_alert->enabled = ALERT_DISABLE;
    }
    else
    {
        if( p_alert->conf.time_pending > 0)
        {
            if( p_alert->handle )
            {
                p_alert->handle( ALERT_OFF );
            }
            p_alert->on = ALERT_OFF;
            p_alert->work.threshold = p_alert->conf.time_pending;
        }
        else 
        {
            if( p_alert->handle )
            {
                p_alert->handle( ALERT_ON );
            }
            p_alert->on = ALERT_ON;
            p_alert->work.threshold = p_alert->conf.time_on;
        }

        p_alert->enabled = ALERT_ENABLE;

        p_alert->work.timer = 0;
        p_alert->work.count = 0; 
        p_alert->work.cycle = 0;

        alert_timer_start();
    }

    alert_desc.update = false; 
}

void alert_disable(int idx)
{
    if( idx >= m_count_of_alerts )
    return;

    m_alert_handles[idx].enabled = ALERT_DISABLE;
    m_alert_handles[idx].handle( ALERT_OFF );
}

void alert_disable_all(void)
{
    for(int i = 0; i < m_count_of_alerts; i++)
    {
        m_alert_handles[i].enabled = ALERT_DISABLE;
        m_alert_handles[i].handle( ALERT_OFF );
    }
}

int alert_channel_add( const alert_conf_init_t * p_conf, int * p_channel_assign)
{
    if( p_conf == 0 || p_channel_assign == 0)
    return 1;

    if( m_count_of_alerts >= NUMS_OF_ALERT)
    return 1;

    int idx = m_count_of_alerts;
    m_alert_handles[idx].handle = p_conf->handle;
#if ALERT_HAS_CALLBACK_HANDLE
    m_alert_handles[idx].completed = p_conf->completed;
#endif 

    if( m_alert_handles[idx].handle){
        m_alert_handles[idx].handle( ALERT_OFF ); //turn off 
    }

    *p_channel_assign = idx;

    m_count_of_alerts ++; 

    return 0; 
}


int alert_init( const alert_conf_init_list_t * p_init_list)
{
    if( p_init_list == NULL || p_init_list->count > NUMS_OF_ALERT){
        return 1;
    }

    m_count_of_alerts = 0;
    
    int i = 0;
    for( i = 0; i < p_init_list->count; i++)
    {
        m_alert_handles[i].handle = p_init_list->p_list[i].handle;
//        m_alert_handles[i].completed = p_init_list->p_list[i].completed;

        if( m_alert_handles[i].handle)
        {
            m_alert_handles[i].handle( ALERT_OFF ); 
        }

        m_count_of_alerts ++; 
    }
    
//    m_cb = p_init_list->completed;
    alert_timer_create();

    return m_count_of_alerts; 
}

#endif
